package com.lyncs.ods.modules.setting.controller;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.lyncs.ods.common.api.CommonResult;
import com.lyncs.ods.common.api.Option;
import com.lyncs.ods.constant.CurrencyEnum;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.modules.goods.model.SpuCategoryInfo;
import com.lyncs.ods.modules.goods.service.SpuCategoryInfoService;
import com.lyncs.ods.modules.setting.model.*;
import com.lyncs.ods.modules.setting.service.AppSettingService;
import com.lyncs.ods.modules.setting.service.CountryInfoService;
import com.lyncs.ods.modules.setting.service.IndustryInfoService;
import com.lyncs.ods.modules.setting.service.PaymentSettingService;
import com.lyncs.ods.resp.IndustryInfoResp;
import com.lyncs.ods.resp.PaymentSettingResp;
import com.lyncs.ods.utils.PageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * sku信息 前端控制器
 * </p>
 *
 * @author alex
 * @since 2022-02-05
 */
@RestController
@RequestMapping("/settings")
@Api(tags = {"系统配置项相关接口"})
@Slf4j
public class SettingController {

    @Autowired
    private PaymentSettingService paymentSettingService;
    @Autowired
    private IndustryInfoService industryInfoService;
    @Autowired
    private SpuCategoryInfoService spuCategoryInfoService;
    @Autowired
    private CountryInfoService countryInfoService;
    @Autowired
    private AppSettingService appSettingService;

    @GetMapping("/list")
    @ApiOperation(value = "获取系统相关说明")
    public CommonResult<List<Setting>> listSpuInfo() {
        SerializeConfig serializeConfig = new SerializeConfig();
        List<Setting> settings = Arrays.stream(LyncsOdsConstant.SystemConfig.values())
                .map(item -> {
                    Enum<? extends Enum<?>>[] enumConstants = item.getClazz().getEnumConstants();
                    if (ArrayUtil.isEmpty(enumConstants)) {
                        return null;
                    }
                    //noinspection unchecked
                    serializeConfig.configEnumAsJavaBean(item.getClazz());
                    List<JSONObject> configs = Arrays.stream(enumConstants)
                            .map(enumConstant -> JSONObject.toJSONString(enumConstant, serializeConfig))
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList());
                    log.info("{}", JSON.toJSONString(configs));
                    return new Setting()
                            .setKey(item.getKey())
                            .setDesc(item.getDesc())
                            .setConfigs(configs);
                }).filter(Objects::nonNull).collect(Collectors.toList());
        return CommonResult.success(settings);
    }

    @GetMapping("/payments")
    @ApiOperation(value = "获取系统所有支持的支付方式")
    public CommonResult<List<PaymentSettingResp>> listPaymentsInfo() {
        List<PaymentSetting> paymentSettings = paymentSettingService.lambdaQuery().eq(PaymentSetting::getStatus, 1).list();
        if (CollectionUtils.isEmpty(paymentSettings)) {
            return CommonResult.success();
        }
        List<PaymentSettingResp> settings = paymentSettings.stream().map(i -> {
            PaymentSettingResp resp = new PaymentSettingResp();
            BeanUtils.copyProperties(i, resp);
            resp.setPaymentId(i.getId());
            String attrJson = i.getAttrJson();
            JSONObject attrs = JSON.parseObject(attrJson);
            resp.setAttrInfos(attrs.entrySet().stream().map(attr -> new PaymentAttr().setKey(attr.getKey()).setLabel(attr.getValue().toString())).collect(Collectors.toList()));
            return resp;
        }).collect(Collectors.toList());
        return CommonResult.success(settings);
    }
    @GetMapping("{key}/list")
    @ApiOperation(value = "根据key获取指定配置项")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "key", value = "key", dataType = "String", paramType = "path", allowableValues = "industry,category,country,currency,companyAvatar,userAvatar,companyBackground,virtualCompanyAvatar,virtualCompanyBackground"),
            @ApiImplicitParam(name = "keyword", value = "过滤关键字", dataType = "String", paramType = "query"),
    })
    public CommonResult<Object> listSettingByKey(@PathVariable String key,
                                                 @RequestParam(value = "keyword", required = false) String keyword) {
        List<String> appSettingKeys = List.of("companyAvatar", "userAvatar", "companyBackground", "virtualCompanyAvatar", "virtualCompanyBackground");
        List<Option<String, String>> options = new ArrayList<>();
        //TODO:后续考虑引入设计模式优化
        if ("industry".equals(key)) {
            List<IndustryInfo> industryInfos = industryInfoService.listAvailable(keyword);
            Map<Long, String> parentNameMap = industryInfos.stream().filter(info -> info.getParentId() == 0).collect(Collectors.toMap(IndustryInfo::getId, IndustryInfo::getName));
            Map<Long, List<IndustryInfo>> subIndustryInfoMap = industryInfos.stream().filter(info -> info.getParentId() != 0).collect(Collectors.groupingBy(IndustryInfo::getParentId));
            return CommonResult.success(parentNameMap.entrySet().stream().map(p -> new IndustryInfoResp()
                    .setId(p.getKey()).setName(p.getValue())
                    .setSubInfos(subIndustryInfoMap.getOrDefault(p.getKey(), new ArrayList<>()).stream().map(s -> Map.of(s.getId().toString(), s.getName())).collect(Collectors.toList()))).collect(Collectors.toList()));
        } else if ("category".equals(key)) {
            List<SpuCategoryInfo> categoryInfos = spuCategoryInfoService.lambdaQuery()
                    .eq(SpuCategoryInfo::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey())
                    .like(StringUtils.isNotEmpty(keyword), SpuCategoryInfo::getName, keyword)
                    .list();
            options = categoryInfos.stream().map(category -> new Option<String, String>().setKey(category.getId().toString()).setValue(category.getName())).collect(Collectors.toList());
        } else if ("country".equals(key)) {
            List<CountryInfo> countryInfos = countryInfoService.listAvailable(keyword);
            options = countryInfos.stream().map(country -> new Option<String, String>().setKey(country.getId().toString()).setValue(country.getName())).collect(Collectors.toList());
        } else if ("currency".equals(key)) {
            options = Stream.of(CurrencyEnum.values())
                    .filter(i -> Objects.isNull(keyword) || i.getCurrency().contains(keyword))
                    .filter(i -> LyncsOdsConstant.EnableStatus.ENABLE.getKey().equals(i.getStatus()))
                    .map(i -> new Option<String, String>().setKey(i.getCurrency()).setValue(i.getDescription())).
                    collect(Collectors.toList());
        } else if (appSettingKeys.contains(key)) {
            AppSetting backgroundImage = appSettingService.lambdaQuery().eq(AppSetting::getSettingKey, key)
                    .eq(AppSetting::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey())
                    .last(PageUtil.getLastSql(1, 1))
                    .one();
            return CommonResult.success(JSONArray.parseArray(backgroundImage.getSettingValue()));
        }
        return CommonResult.success(options);
    }

    @Data
    @Accessors(chain = true)
    private static class Setting {
        private String key;
        private String desc;
        private List<JSONObject> configs;
    }
}

